package api

import (
	"encoding/json"
	"io/ioutil"
	"ipbc0/core"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type Resp struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

func Ok() (b []byte, err error) {
	var resp *Resp
	resp = &Resp{
		Code: 0,
		Msg:  "ok",
	}
	b, err = json.Marshal(resp)
	return
}

func Err(msg string) (b []byte, err error) {
	var resp *Resp
	resp = &Resp{
		Code: -1,
		Msg:  msg,
	}
	b, err = json.Marshal(resp)
	return
}

type TaskReq struct {
	JobID     int      `json:"jobId"`
	Level     int      `json:"level"`
	Type      int      `json:"type"`
	LoopCnt   int      `json:"loopCnt"`
	DeviceIds []string `json:"deviceIds"`
	FileIds   []int    `json:"fileIds"`
	EndTime   int64    `json:"endTime"`
}

func StartTask(w http.ResponseWriter, r *http.Request) {
	s, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println(err)
		b, _ := Err("read err")
		w.Write(b)
		return
	}

	ctx := core.GetCtx()

	var tr TaskReq
	err = json.Unmarshal(s, &tr)
	if err != nil {
		b, _ := Err("json Unmarshal err")
		w.Write(b)
		return
	}

	log.Println(tr.JobID)
	log.Println(tr.FileIds)

	var task *core.Task
	task = ctx.TaskCache[tr.JobID]
	if task == nil {
		task = &core.Task{
			TaskID:     tr.JobID,
			Level:      tr.Level,
			Type:       tr.Type,
			LoopCnt:    tr.LoopCnt,
			DevIDs:     tr.DeviceIds,
			PcmFiles:   tr.FileIds,
			EndTime:    tr.EndTime,
			CreateTime: time.Now().Unix() / 1e6,

			Stop: false,
		}
		go task.Run()
		ctx.TaskCache[task.TaskID] = task
	}

	b, _ := Ok()
	w.Write(b)
}

func StopTask(w http.ResponseWriter, r *http.Request) {
	s, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println(err)
		b, _ := Err("read err")
		w.Write(b)
		return
	}

	ctx := core.GetCtx()

	var tr TaskReq
	err = json.Unmarshal(s, &tr)
	if err != nil {
		b, _ := Err("json Unmarshal err")
		w.Write(b)
		return
	}

	var task *core.Task
	task = ctx.TaskCache[tr.JobID]

	if task != nil {
		task.Stop = true
		delete(ctx.TaskCache, tr.JobID)
	}

	b, _ := Ok()
	w.Write(b)
}

type DevListResp struct {
	Code int        `json:"code"`
	Msg  string     `json:"msg"`
	Data []core.Dev `json:"data"`
}

func ListDevice(w http.ResponseWriter, r *http.Request) {
	ctx := core.GetCtx()
	devs := make([]core.Dev, 0)
	for _, dev := range ctx.DevCache {
		devs = append(devs, *dev)
	}
	resp := &DevListResp{
		Code: 0,
		Msg:  "ok",
		Data: devs,
	}

	b, _ := json.Marshal(resp)
	w.Write(b)
}

type CheckSpeechResp struct {
	Code int                  `json:"code"`
	Msg  string               `json:"msg"`
	Data *CheckSpeechRespData `json:"data"`
}

type CheckSpeechRespData struct {
	OnSpeechDeviceList  []string `json:"onSpeechDeviceList"`
	OnPlayingDeviceList []string `json:"onPlayingDeviceList"`
}

func CheckSpeech(w http.ResponseWriter, r *http.Request) {
	s, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println(err)
		b, _ := Err("read err")
		w.Write(b)
		return
	}

	var devIDs []string
	err = json.Unmarshal(s, &devIDs)
	if err != nil {
		b, _ := Err("json Unmarshal err")
		w.Write(b)
		return
	}

	ctx := core.GetCtx()

	onSpeechDeviceList := make([]string, 0)
	onPlayingDeviceList := make([]string, 0)
	for _, devID := range devIDs {
		dev := ctx.DevCache[devID]
		if dev != nil {
			if dev.Locked {
				onSpeechDeviceList = append(onSpeechDeviceList, dev.DevID)
			}
			if dev.CurrentTask != nil {
				onPlayingDeviceList = append(onPlayingDeviceList, dev.DevID)
			}
		}
	}

	checkSpeechRespData := &CheckSpeechRespData{
		OnSpeechDeviceList:  onSpeechDeviceList,
		OnPlayingDeviceList: onPlayingDeviceList,
	}

	resp := &CheckSpeechResp{
		Code: 0,
		Msg:  "ok",
		Data: checkSpeechRespData,
	}

	b, _ := json.Marshal(resp)
	w.Write(b)
}

type OpenSpeechResp struct {
	Code int      `json:"code"`
	Msg  string   `json:"msg"`
	Data []string `json:"data"`
}

func OpenSpeech(w http.ResponseWriter, r *http.Request) {
	s, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println(err)
		b, _ := Err("read err")
		w.Write(b)
		return
	}

	var devIDs []string
	err = json.Unmarshal(s, &devIDs)
	if err != nil {
		b, _ := Err("json Unmarshal err")
		w.Write(b)
		return
	}

	uri := r.RequestURI

	parts := strings.Split(uri, "/")
	for i, p := range parts {
		log.Println(strconv.Itoa(i) + "-" + p)
	}

	if len(parts) < 7 {
		b, _ := Err("param err")
		w.Write(b)
		return
	}

	userID, err := strconv.Atoi(parts[5])
	if err != nil {
		b, _ := Err(err.Error())
		w.Write(b)
		return
	}

	lockedByLevel, err := strconv.Atoi(parts[6])
	if err != nil {
		b, _ := Err(err.Error())
		w.Write(b)
		return
	}

	ctx := core.GetCtx()
	lockedDevIDs := make([]string, 0)
	for _, devID := range devIDs {
		dev := ctx.DevCache[devID]
		if dev != nil {
			if !dev.Locked {
				dev.Locked = true
				dev.LockedByUserID = userID
				dev.LockedByLevel = lockedByLevel
				dev.SpeechPacketTime = time.Now().Unix() / 1e6
				dev.OpenSound()
				lockedDevIDs = append(lockedDevIDs, devID)

				online := false
				if dev.Ts > time.Now().Unix()/1e6-60000 {
					online = true
				}

				onPlaying := false
				if dev.CurrentTask != nil {
					onPlaying = true
				}

				// open speech msg
				msg := &core.DevStatusMsg{
					MsgType:        1,
					DevID:          dev.DevID,
					IP:             dev.IP,
					OnSpeech:       true,
					OnPlaying:      onPlaying,
					Online:         online,
					Mode:           dev.Mode,
					LockedByUserID: userID,
					Time:           dev.Ts,
				}
				b, _ := json.Marshal(msg)
				ctx.S1.Broadcast(b)
			} else {
				if lockedByLevel < dev.LockedByLevel {
					dev.Locked = true
					dev.LockedByUserID = userID
					dev.LockedByLevel = lockedByLevel
					dev.SpeechPacketTime = time.Now().Unix() / 1e6
					dev.OpenSound()
					lockedDevIDs = append(lockedDevIDs, devID)

					online := false
					if dev.Ts > time.Now().Unix()/1e6-60000 {
						online = true
					}

					onPlaying := false
					if dev.CurrentTask != nil {
						onPlaying = true
					}

					// open speech msg
					msg := &core.DevStatusMsg{
						MsgType:        1,
						DevID:          dev.DevID,
						IP:             dev.IP,
						OnSpeech:       true,
						OnPlaying:      onPlaying,
						Online:         online,
						Mode:           dev.Mode,
						LockedByUserID: userID,
						Time:           dev.Ts,
					}
					b, _ := json.Marshal(msg)
					ctx.S1.Broadcast(b)
				}
			}
		}
	}

	resp := &OpenSpeechResp{
		Code: 0,
		Msg:  "ok",
		Data: lockedDevIDs,
	}
	b, _ := json.Marshal(resp)
	w.Write(b)
}

func CloseSpeech(w http.ResponseWriter, r *http.Request) {
	ctx := core.GetCtx()

	uri := r.RequestURI

	parts := strings.Split(uri, "/")
	for i, p := range parts {
		log.Println(strconv.Itoa(i) + "-" + p)
	}

	if len(parts) < 6 {
		b, _ := Err("param err")
		w.Write(b)
		return
	}

	userID, err := strconv.Atoi(parts[5])
	if err != nil {
		b, _ := Err(err.Error())
		w.Write(b)
		return
	}

	for _, dev := range ctx.DevCache {
		if dev != nil && dev.LockedByUserID == userID {
			dev.Locked = false
			dev.LockedByLevel = 0
			dev.LockedByUserID = 0
			dev.SpeechPacketTime = 0
		}
	}

	b, _ := Ok()
	w.Write(b)
}

func HeartbeatAll(w http.ResponseWriter, r *http.Request) {
	s, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println(err)
		b, _ := Err("read err")
		w.Write(b)
		return
	}

	var devIDs []string
	err = json.Unmarshal(s, &devIDs)
	if err != nil {
		b, _ := Err("json Unmarshal err")
		w.Write(b)
		return
	}

	ctx := core.GetCtx()
	for _, devID := range devIDs {
		dev := ctx.DevCache[devID]
		if dev != nil {
			dev.Heartbeat()
		}
	}

	b, _ := Ok()
	w.Write(b)
}
